package it.marco.test.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Projections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

public abstract class AbstractBaseDAO<T, ID extends Serializable> implements BaseDAO<T, ID> {
	
	private Class<T> persistentClass;
	
	
	@Autowired
	protected HibernateTemplate hibernateTemplate;
//	protected SessionFactory sessionFactory;

	@SuppressWarnings("unchecked")
	public AbstractBaseDAO() {
		this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}
	
//	@Autowired
//	public void setSessionFactory(SessionFactory sessionFactory) {
//		this.sessionFactory = sessionFactory;
//	}

	public Class<T> getPersistentClass() {
		return persistentClass;
	}

	/* (non-Javadoc)
	 * @see it.marco.test.dao.BaseDAO#find(ID)
	 */
	public T find(ID id) {
//		return (T)sessionFactory.getCurrentSession().get(persistentClass, id); // find(persistentClass, id);
		return this.hibernateTemplate.get(persistentClass, id);
	}

	/* (non-Javadoc)
	 * @see it.marco.test.dao.BaseDAO#persist(T)
	 */
	public void save(T entity) {
		this.hibernateTemplate.save(entity);
//		sessionFactory.getCurrentSession().save(entity);
	}

	/* (non-Javadoc)
	 * @see it.marco.test.dao.BaseDAO#merge(T)
	 */
	public void saveOrUpdate(T entity) {
//		sessionFactory.getCurrentSession().saveOrUpdate(entity);
		this.hibernateTemplate.saveOrUpdate(entity);
	}
	
	public void update(T entity) {
		this.hibernateTemplate.update(entity);
		
	}

	/* (non-Javadoc)
	 * @see it.marco.test.dao.BaseDAO#remove(T)
	 */
	public void delete(T entity) {
//		sessionFactory.getCurrentSession().delete(entity);
		this.hibernateTemplate.delete(entity);
	}

	/* (non-Javadoc)
	 * @see it.marco.test.dao.BaseDAO#findAll()
	 */
	@SuppressWarnings("unchecked")
	public List<T> findAll() {
		return this.hibernateTemplate.execute(new HibernateCallback<List<T>>() {
			public List<T> doInHibernate(Session session) throws HibernateException,
					SQLException {
				return session.createCriteria(persistentClass).list();
				
			}
		});
//		return sessionFactory.getCurrentSession().createCriteria(persistentClass).list();
	}

	/* (non-Javadoc)
	 * @see it.marco.test.dao.BaseDAO#findInRange(int, int)
	 */
	@SuppressWarnings("unchecked")
	public List<T> findInRange(final int firstResult, final int maxResults) {
		return this.hibernateTemplate.execute(new HibernateCallback<List<T>>() {
			public List<T> doInHibernate(Session session) throws HibernateException,
					SQLException {
				Criteria c = session.createCriteria(persistentClass);
				c.setFirstResult(firstResult);
				c.setMaxResults(maxResults);
				return c.list();
			}
		});
		//return sessionFactory.getCurrentSession().createCriteria(persistentClass).list();
		//return entityManager.createQuery("Select t from " + persistentClass.getSimpleName() + " t").setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
	}

	public long count() {
		return this.hibernateTemplate.execute(new HibernateCallback<Long>() {
			public Long doInHibernate(Session session) throws HibernateException,
					SQLException {
				Criteria c = session.createCriteria(persistentClass);
				c.setProjection(Projections.rowCount());
				return new Long(c.list().size());
				
			}
		});
//		return sessionFactory.getCurrentSession().createCriteria(persistentClass).list().size();
		//return (Long) entityManager.createQuery("Select count(t) from " + persistentClass.getSimpleName() + " t").getSingleResult();
	}

	
}
